package com.chu.cloud.service.impl;

import com.chu.cloud.entity.User;
import com.chu.cloud.entity.mongo.AuthAccessToken;
import com.chu.cloud.enums.RedisKeyPrefix;
import com.chu.cloud.enums.ResultEnums;
import com.chu.cloud.enums.UserGradeEnum;
import com.chu.cloud.repository.AuthAccessTokenDao;
import com.chu.cloud.repository.UserRepository;
import com.chu.cloud.util.*;
import com.chu.cloud.vo.UserVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.Optional;

/**
 * @author: Tianshu.CHU
 * @Date: 2018/3/26 16:48
 * @Description:
 */
@Service
@Slf4j
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private AuthAccessTokenService accessTokenService;

    @Autowired
    private AuthAccessTokenDao accessTokenDao;

    @Transactional(rollbackFor = Exception.class)
    public String loginByMobile(String mobile, String validateCode, String ip) {
        User user = userRepository.findByMobile(mobile);
        String cacheValidCode = RedisUtil.get(RedisKeyPrefix.MOBILE_SMSCODE, mobile, String.class);
        //验证码过期或错误
        if (!validateCode.equals(cacheValidCode)) {
            ChuException.throwException(ResultEnums.ALIDATE_DUCE);
        }
        if (user == null) {
            //后台注册逻辑
            User registerUser = register(mobile, ip);
            //插入mongodb
            UserVo userVo = new UserVo();
            BeanUtil.copyProperties(userVo,registerUser);
            AuthAccessToken accessToken = accessTokenService.saveToken(registerUser.getId(), registerUser.getUserName(), registerUser.getMobile(), ip);
            RedisUtil.set(RedisKeyPrefix.TOKEN_MEMBER, accessToken.getToken(), userVo, 3600);
            log.info("---该用户未注册,后台默认注册,生成token{}", accessToken.getToken());
            return accessToken.getToken();
        }
        if (user.getStatus() == 1) {
            ChuException.throwException(ResultEnums.USER_DISABLED);
        }
        user.setLoginNum(user.getLoginNum() + 1);
        user = userRepository.save(user);
        UserVo userVo = new UserVo();
        BeanUtil.copyProperties(userVo,user);
        AuthAccessToken authAccessToken = accessTokenService.saveToken(user.getId(), user.getUserName(), user.getMobile(), ip);
        RedisUtil.set(RedisKeyPrefix.TOKEN_MEMBER, authAccessToken.getToken(), userVo, 3600);
        log.info("保存到redis成功{}", JsonUtils.obj2json(userVo));
        return authAccessToken.getToken();

    }

    private User register(String mobile, String ip) {
        User user;
        user = new User();
        user.setMobile(mobile);
        user.setGrade(UserGradeEnum.V1);
        user.setLoginNum(1);
        user.setUserName(mobile);
        user.setRegisterIp(ip);
        user.setRegisterTime(new Date());
        user.setStatus(0);
        return userRepository.save(user);
    }

    /**
     * 根据Token查询用户信息
     * <p>
     * 1.先去redis里面查,如果redis有则返回
     * 2.redis不存在,说明太久没有登录了,key失效
     * 3.查询mongodb,30失效时间,直接返回
     * 4.若mongodb也失效,重新登录
     * 5.更新缓存失效时间
     *
     * @param token
     * @return
     */
    public UserVo findByToken(String token) {
        AuthAccessToken accessToken = accessTokenService.findToken(token);
        log.info("查询mongodb:{}", JsonUtils.obj2json(accessToken));
        if (accessToken != null && accessToken.getExpireTime().after(new Date())) {
            accessToken.setExpireTime(DateUtils.dayOffset(new Date(), 30));
            accessTokenDao.save(accessToken);
            User userDb = Optional.ofNullable(userRepository.findOne(accessToken.getUserId())).
                    orElseThrow(() -> new IllegalArgumentException("查无此用户"));
            UserVo userVo = new UserVo();
            BeanUtil.copyProperties(userVo,userDb);
            RedisUtil.set(RedisKeyPrefix.TOKEN_MEMBER, token, userVo, 3600);
            return userVo;
        }
        return null;
    }
}
